package com.zusmart.base.looper.support;

import com.zusmart.base.activity.support.AbstractActivity;
import com.zusmart.base.logging.Logger;
import com.zusmart.base.logging.LoggerFactory;
import com.zusmart.base.looper.EventLoop;
import com.zusmart.base.looper.EventLoopGroup;
import com.zusmart.base.toolkit.FixedAtomicInteger;
import com.zusmart.base.util.Assert;

public abstract class AbstractEventLoopGroup extends AbstractActivity<EventLoopGroup> implements EventLoopGroup {

	private static final Logger logger = LoggerFactory.getLogger(AbstractEventLoopGroup.class);

	private final String eventLoopName;
	private final EventLoop[] eventLoopPool;
	private final FixedAtomicInteger eventLoopIndex;

	protected AbstractEventLoopGroup(int eventLoopSize, String eventLoopName) {
		Assert.isTrue(eventLoopSize <= 0, "event loop size must > 0");
		Assert.isBlank(eventLoopName, "event loop name must not be blank");
		this.eventLoopName = eventLoopName;
		this.eventLoopPool = new EventLoop[eventLoopSize];
		this.eventLoopIndex = new FixedAtomicInteger(0, eventLoopSize - 1);
	}

	@Override
	public int getEventLoopSize() {
		return this.eventLoopPool.length;
	}

	@Override
	public EventLoop getEventLoop() {
		return this.getEventLoop(this.eventLoopIndex.getAndIncrement());
	}

	@Override
	public EventLoop getEventLoop(int index) {
		return this.eventLoopPool[index];
	}

	@Override
	protected EventLoopGroup getActivity() {
		return this;
	}

	@Override
	protected void doStart() throws Exception {
		for (int i = 0; i < this.eventLoopPool.length; i++) {
			this.eventLoopPool[i] = this.createEventLoop(String.format("%s-%d", this.eventLoopName, i));
		}
		for (int i = 0; i < this.eventLoopPool.length; i++) {
			this.eventLoopPool[i].start();
		}
	}

	@Override
	protected void doClose() throws Exception {
		for (int i = 0; i < this.eventLoopPool.length; i++) {
			try {
				this.eventLoopPool[i].close();
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		}
	}

	protected abstract EventLoop createEventLoop(String name);

}